package com.gzc.util;

import com.gzc.pojo.School;
import com.sun.org.apache.regexp.internal.RE;
import org.apache.commons.lang3.StringUtils;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.Date;
import java.util.HashMap;
import java.util.List;

/**
 *
 * ClassName: QueryListUtil
 * Description: TODO(用一句话描述这个类的作用)
 *
 * @author ganzhancheng
 * @date: 2017年10月25日 上午11:21:24
 * @version v1.0
 * @since JDK 1.7
 */
public class QueryListUtil {
    private List<ConditionBean> conditionList = new ArrayList<>();

    private Integer pageNumber;

    private Integer pageSize;

    private String orderFieldName;

    private OrderDirection orderDirection;

	private static QueryListUtil queryListUtil;

	private QueryListUtil(){}

    public static QueryListUtil getInstance(){
        queryListUtil =  new QueryListUtil();
        return queryListUtil;
    }

    public QueryListUtil addCondition(String fieldName, Object value,ConditionName conditionName){
        ConditionBean conditionKV = new ConditionBean();
        conditionKV.setKey(fieldName);
        conditionKV.setValue(value);
        conditionKV.setCondition(conditionName);
        conditionList.add(conditionKV);
        return queryListUtil;
    }

    public QueryListUtil addEqualCondition(String fieldName, Object value){
        ConditionBean conditionKV = new ConditionBean();
        conditionKV.setKey(fieldName);
        conditionKV.setValue(value);
        conditionKV.setCondition(ConditionName.EQUAL);
        conditionList.add(conditionKV);
        return queryListUtil;
    }

    public QueryListUtil addInCondition(String fieldName, List value){
        ConditionBean conditionKV = new ConditionBean();
        conditionKV.setKey(fieldName);
        conditionKV.setValue(value);
        conditionKV.setCondition(ConditionName.IN);
        conditionList.add(conditionKV);
        return queryListUtil;
    }
    public QueryListUtil addGeaterThanCondition(String fieldName, Object value){
        ConditionBean conditionKV = new ConditionBean();
        conditionKV.setKey(fieldName);
        conditionKV.setValue(value);
        conditionKV.setCondition(ConditionName.GREATER_THAN);
        conditionList.add(conditionKV);
        return queryListUtil;
    }
    public QueryListUtil addLessThanCondition(String fieldName, Object value){
        ConditionBean conditionKV = new ConditionBean();
        conditionKV.setKey(fieldName);
        conditionKV.setValue(value);
        conditionKV.setCondition(ConditionName.LESS_THAN);
        conditionList.add(conditionKV);
        return queryListUtil;
    }

    public QueryListUtil limit(Integer pageNumber, Integer pageSize){
	    this.pageNumber = pageNumber;
        this.pageSize = pageSize;
        return queryListUtil;
    }
    public QueryListUtil orderBy(String orderFieldName,OrderDirection orderDirection){
	    this.orderFieldName = orderFieldName;
        this.orderDirection = orderDirection;
        return queryListUtil;
    }



    public void clearCondition(){
        conditionList.clear();
    }

    /**
     *
     * @param list 需要查询的集合
     * @return 符合条件的集合
     */
    public <T>List<T> query(List<T> list)  {

        try {
			if (orderDirection !=null && StringUtils.isNotBlank(orderFieldName)) {
				list.sort(new Comparator<T>() {
					@Override
					public int compare(T o1, T o2) {
						Class<?> o1Class = o1.getClass();
						try {
							Field o1Field = o1Class.getDeclaredField(orderFieldName);
							o1Field.setAccessible(true);
							Object o1Value = o1Field.get(o1);

							Class<?> o2Class = o2.getClass();
							Field o2Field = o2Class.getDeclaredField(orderFieldName);
							o2Field.setAccessible(true);
							Object o2Value = o2Field.get(o2);

							Class<?> type = o1Field.getType();
							if (type.equals(Date.class)) {
								Date date1 = (Date) o1Value;
								Date date2 = (Date) o2Value;
								if (orderDirection.equals(OrderDirection.DESC)) {
									return (int) (date1.getTime() - date2.getTime());
								} else {
									return (int) (date2.getTime() - date1.getTime());
								}
							} else {
								Double i1 = Double.parseDouble(o1Value.toString());
								Double i2 = Double.parseDouble(o2Value.toString());
								if (orderDirection.equals(OrderDirection.ASC)) {
									return (int) (i1 - i2);
								} else {
									return (int) (i2 - i1);
								}
							}
						} catch (NoSuchFieldException | IllegalAccessException e) {
							e.printStackTrace();
						}
						return 0;
					}
				});
			}

            list = getList(list);

            if (pageSize != null && pageNumber != null) {
                ArrayList<T> pageList = new ArrayList<>();
                int currIdx = (pageNumber > 1 ? (pageNumber -1) * pageSize : 0);
                for (int i = 0; i < pageSize && i < list.size() - currIdx; i++) {
                    T s = list.get(currIdx + i);
                    pageList.add(s);
                }
                return pageList;
            }
            return list;
        } catch (NoSuchFieldException | IllegalAccessException e) {
            e.printStackTrace();
        }

		return new ArrayList<>();
    }

    private <T> List<T> getList(List<T> list) throws NoSuchFieldException, IllegalAccessException {
        ArrayList<T> arrayList = new ArrayList<>();
        for (T o : list) {
            boolean flag = false;
            for (ConditionBean bean : conditionList) {
                Class<?> aClass = o.getClass();
                ConditionName conditionName = bean.getCondition();

                String key = bean.getKey();
                Field declaredField = aClass.getDeclaredField(key);
                String fieldName = declaredField.getName();
                declaredField.setAccessible(true);

                if (conditionName.equals(ConditionName.EQUAL)) {
                    Object value = bean.getValue();
                    flag = compareAndAdd( o, key, declaredField, fieldName, value);
                } else if (conditionName.equals(ConditionName.IN)) {
                    List listValue = (List) bean.getValue();
                    for (Object value : listValue) {
                        flag = compareAndAdd(o, key, declaredField, fieldName, value);
                        if (flag) {
                            break;
                        }
                    }
                } else if (conditionName.equals(ConditionName.GREATER_THAN)) {
                    Class<?> type = declaredField.getType();
                    Object value = bean.getValue();
                    if (type.equals(Date.class) && value instanceof Date) {
                        Date fieldValue = (Date)declaredField.get(o);
                        Date compareValue = (Date) value;
                        if (fieldValue!=null && fieldValue.after(compareValue)) {
                            flag= true;
                        }else{
                            flag =false;
                        }
                    }else {
                        Object fieldValue = declaredField.get(o);
                        if (fieldValue != null) {
                            double d = Double.parseDouble(fieldValue.toString());
                            double compare = Double.parseDouble(value.toString());
                            if (d > compare) {
                                flag= true;
                            }else{
                                flag =false;
                            }
                        }
                    }
                }else if (conditionName.equals(ConditionName.LESS_THAN)) {
                    Class<?> type = declaredField.getType();
                    Object value = bean.getValue();
                    if (type.equals(Date.class) && value instanceof Date) {
                        Date fieldValue = (Date) declaredField.get(o);
                        Date compareValue = (Date) value;
                        if (fieldValue!=null && fieldValue.before(compareValue)) {
                            flag= true;
                        }else{
                            flag =false;
                        }
                    } else {
                        Object fieldValue = declaredField.get(o);
                        if (fieldValue != null) {
                            double d = Double.parseDouble(fieldValue.toString());
                            double compare = Double.parseDouble(value.toString());
                            if (d < compare) {
                                flag= true;
                            }else{
                                flag =false;
                            }
                        }
                    }
                }


            }
            if (flag) {
                arrayList.add(o);
            }
        }
        return arrayList;
    }

	private <T> boolean compareAndAdd(T o, String key, Field declaredField, String fieldName, Object value) throws IllegalAccessException {
		Object fieldValue = declaredField.get(o);
		if(fieldValue==null||value==null){
			return false;
		}
        double d1 = Double.parseDouble(fieldValue.toString());
        double d2 = Double.parseDouble(value.toString());
        if (key.equals(fieldName) && d1 == d2) {
			return true;
		}
        return false;
	}

	private class ConditionBean {
        String key;
        Object value;
        ConditionName condition;
        ConditionName getCondition() {
            return condition;
        }

        void setCondition(ConditionName condition) {
            this.condition = condition;
        }

        String getKey() {
            return key;
        }

        void setKey(String key) {
            this.key = key;
        }

        Object getValue() {
            return value;
        }

        void setValue(Object value) {
            this.value = value;
        }
    }

    private class Page{

    }

    public enum ConditionName{
        IN,EQUAL,GREATER_THAN,LESS_THAN
    }

	public enum OrderDirection{
		ASC,DESC
	}

    public static void copyListProperties(List<?> target, List<?> source, String equalProperty, String tartProperty) {

        try {
            HashMap<String, Object> map = new HashMap<>();
            for (Object o : source) {
                Class<?> sClass = o.getClass();
                Field eqField = sClass.getDeclaredField(equalProperty);
                eqField.setAccessible(true);
                Object eq = eqField.get(o);
                Field targetField = sClass.getDeclaredField(tartProperty);
                targetField.setAccessible(true);
                Object value = targetField.get(o);
                map.put(eq.toString(), value);
            }


            for (Object o : target) {
                Class<?> tClass = o.getClass();
                Field eqField = tClass.getDeclaredField(equalProperty);
                eqField.setAccessible(true);
                Object eq = eqField.get(o);

                Object value = map.get(eq.toString());

                Field targetField =tClass.getDeclaredField(tartProperty);
                targetField.setAccessible(true);
                targetField.set(o,value);
            }
        } catch (NoSuchFieldException | IllegalAccessException e) {
            e.printStackTrace();
        }

	}
}
